package cn.blnp.net.flowable.boot.optimize.timer;

import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

/**
 * <h3>中间事件-定时器中间捕获事件</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/5/9 15:35
 */
@Slf4j
@SpringBootTest
public class MidTimerEvent {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;

    /**
     *  <p>
     *      定时器中间捕获事件指在流程中将一个定时器作为独立的节点来运行，是一个捕获事件。当流程流转到定时器中间捕获事件时，会启动一个定时器，并一直等待触发，
     *   只有到达指定时间，定时器才被触发，然后流程沿着定时器中间事件的外出顺序流继续流转。事件定义格式如下所示：
     *   <pre>
     *       {@code
     *          <process id="timerIntermediateCatchingEventProcess">
     *              <intermediateCatchEvent id="intermediateCatchEvent1">
     *                  <!-- 包含timerEventDefinition子元素，代表定时器中间捕获事件 -->
     *                  <timerEventDefinition>
     *                      <timeDuration>PT5M</timeDuration>
     *                  </timerEventDefinition>
     *              </intermediateCatchEvent>
     *          </process>
     *       }
     *   </pre>
     *  </p><br/>
     *  <h2>案例演示</h2>
     *  <hr/>
     *  <p>
     *      该流程为库房出库的流程：出库申请发起后，需要给一定的时间让库房准备，然后进行出库作业，此时可以嵌入定时器中间捕获事件定义流程自动向下执行的时间间隔。<br/><br/>
     *      <b>流程定义文件：</b>{@code flow/midTimerEvent.bpmn20.xml}<br/>
     *      <b>流程预览图：</b><br/>
     *      <img src="https://free4.yunpng.top/2025/05/09/681db284051b8.png" />
     *  </p>
     **/
    @Test
    public void test() {
        Deployment deploy = repositoryService.createDeployment()
                .name("定时器中间捕获事件案例")
                .addClasspathResource("flow/midTimerEvent.bpmn20.xml")
                .deploy();
        log.info("部署流程定义：{}", deploy.getId());
        ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        log.info("流程定义编号：{}", procDef.getId());
        //启动流程实例
        ProcessInstance procInst = runtimeService.startProcessInstanceById(procDef.getId());
        TaskQuery taskQuery = taskService.createTaskQuery()
                .processInstanceId(procInst.getId());
        //查询并完成第一个任务
        Task firstTask = taskQuery.singleResult();
        log.info("第一个用户任务为：{}", firstTask.getName());
        taskService.complete(firstTask.getId());
        log.info("当前出库申请已完成！");
        //此时休眠等待70秒
        try {
            Thread.sleep(70 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //查询第二个任务
        Task secondTask = taskQuery.singleResult();
        log.info("第二个任务为：{}", secondTask.getName());

        /**
         *  演示结果：
         * 2025-05-09 15:51:23.852  INFO 7328 --- [           main] c.b.n.f.e.middle.timer.MidTimerEvent     : 部署流程定义：670775f6-2caa-11f0-8abe-50ebf6ec8f6d
         * 2025-05-09 15:51:23.856  INFO 7328 --- [           main] c.b.n.f.e.middle.timer.MidTimerEvent     : 流程定义编号：midTimerEvent:1:6757dfe9-2caa-11f0-8abe-50ebf6ec8f6d
         * 2025-05-09 15:51:23.919  INFO 7328 --- [           main] c.b.n.f.e.middle.timer.MidTimerEvent     : 第一个用户任务为：出库申请
         * 2025-05-09 15:51:23.999  INFO 7328 --- [           main] c.b.n.f.e.middle.timer.MidTimerEvent     : 当前出库申请已完成！
         * 2025-05-09 15:52:34.015  INFO 7328 --- [           main] c.b.n.f.e.middle.timer.MidTimerEvent     : 第二个任务为：出库
         **/
    }
}
